#include "singleinstancegrard.h"
#include <qprocess.h>
#include <qcoreapplication.h>
#include <qdebug.h>
#include <qsystemsemaphore.h>
#include <qthread.h>

SingleInstanceGuard::SingleInstanceGuard(const QString&key)
    :m_mem_lock_key{key+"_mem_lock"},m_shared_mem_key{key}
{
    QSystemSemaphore semaphore(m_mem_lock_key,1);
    semaphore.acquire();
    {
        m_memory.setKey(m_shared_mem_key);
        if(m_memory.attach())
        {
            KillExitingInstance();
            m_memory.detach();
        }
    }
    //new memory
    m_memory.setKey(m_shared_mem_key);
    if(m_memory.create(1))
        m_is_primary = true;
    else
    {
        KillExitingInstance();
        ::exit(1);
    }
    semaphore.release();
}

void SingleInstanceGuard::KillExitingInstance()
{
    QProcess process{};
    auto appname{QCoreApplication::applicationName()};
    qDebug()<<"kill this app: "<<appname<<"\r\n";
#if defined (_WIN32) || defined(_WIN64)
    process.start("tasklist",QStringList()<<"/FI"<<QString("IMAGE eq %1").arg(appname)<<"/FO"<<"CSV");
#else
    process.start("pgrep",QStringList()<<"-if"<<appname);
#endif
    process.waitForFinished();

    QString output = process.readAllStandardOutput();
#if defined (_WIN32)||defined (_WIN64)
    if(output.contains(appname))
    {
        QProcess::execute("taskkill",QStringList()<<"/F"<<"/IM"<<appname);
        QThread::msleep(500);
    }
#elif defined(__linux__)
    auto lst = output.split('\n',QString::SkipEmptyParts);
    qint64 current_pid = QCoreApplication::applicationPid();
    for(const auto &pidstr:lst)
    {
        bool bok{false};
        qint64 pid = pidstr.trimmed().toLongLong(&bok);
        if(bok && pid != current_pid && pid>0)
        {
            QProcess::execute("kill",QStringList()<<"-9"<<QString::number(pid));
            qDebug()<<"kill exiting app!"<<"\r\n";
            QThread::msleep(500);
        }
    }
#endif
}

SingleInstanceGuard::~SingleInstanceGuard()
{
    if(m_is_primary)
    {
        QSystemSemaphore semphore(m_mem_lock_key,1);
        semphore.acquire();

        if(m_memory.isAttached())
            m_memory.detach();
        semphore.release();
    }
}
